package com.hopechart.micro.util;

import com.google.common.cache.CacheStats;
import com.google.common.cache.LoadingCache;
import com.hopechart.micro.common.cache.AbstractLoadingCache;
import com.hopechart.micro.common.exception.BusinessException;
import com.hopechart.micro.common.exception.ErrorCode;

import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * <p>
 * <br/>
 * 缓存工具
 * </p>
 *
 * @author daijiang@hopechart.com
 * @version V1.0.0
 * @date 2017-12-06 14:24
 * @copyright 杭州鸿泉数字设备有限公司
 */
public class CacheUtil {

	private static Map<String, ? extends AbstractLoadingCache<Object, Object>> cacheNameToObjectMap = null;

	private static Map<String, ? extends AbstractLoadingCache<Object, Object>> getCacheMap() {
		if (cacheNameToObjectMap == null) {
			cacheNameToObjectMap = (Map<String, ? extends AbstractLoadingCache<Object, Object>>)
                    SpringContextUtil.getBeanOfType(AbstractLoadingCache.class);
		}
		return cacheNameToObjectMap;

	}

	public static Object getValue(String cacheName, String key) {
		try {
			LoadingCache loadingCache = getCacheByName(cacheName).getCache();
			Object obj = loadingCache.get(key);
			return obj;
		} catch (Exception e) {
			throw new BusinessException(ErrorCode.CACHE_READ, e);
		}
	}

	public static AbstractLoadingCache<Object, Object> getCacheByName(String cacheName) {
		return getCacheMap().get(cacheName);
	}

	public static Set<String> getCacheNames() {
		return getCacheMap().keySet();
	}

	public static ArrayList<Map<String, Object>> getAllCacheStats() {
		Map<String, ? extends Object> cacheMap = getCacheMap();
		List<String> cacheNameList = new ArrayList<>(cacheMap.keySet());
		// 按照字母排序
		Collections.sort(cacheNameList);

		// 遍历所有缓存，获取统计数据
		ArrayList<Map<String, Object>> list = new ArrayList<>();
		for (String cacheName : cacheNameList) {
			list.add(getCacheStatsToMap(cacheName));
		}

		return list;
	}

	private static Map<String, Object> getCacheStatsToMap(String cacheName) {
		Map<String, Object> map = new LinkedHashMap<>();
		AbstractLoadingCache<Object, Object> cache = getCacheByName(cacheName);
		CacheStats cs = cache.getCache().stats();
		NumberFormat percent = NumberFormat.getPercentInstance();
		percent.setMaximumFractionDigits(1);
		map.put("cacheName", cacheName);
		map.put("size", cache.getCache().size());
		map.put("maximumSize", cache.getMaximumSize());
		map.put("survivalDuration", cache.getExpireAfterWriteDuration());
		map.put("hitCount", cs.hitCount());
		map.put("hitRate", percent.format(cs.hitRate()));
		map.put("missRate", percent.format(cs.missRate()));
		map.put("loadSuccessCount", cs.loadSuccessCount());
		map.put("loadExceptionCount", cs.loadExceptionCount());
		map.put("totalLoadTime", cs.totalLoadTime() / 1000000);
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		if (cache.getResetTime() != null) {
			map.put("resetTime", df.format(cache.getResetTime()));
		}
		map.put("highestSize", cache.getHighestSize());
		if (cache.getHighestTime() != null) {
			map.put("highestTime", df.format(cache.getHighestTime()));
		}

		return map;
	}

	public static void resetCache(String cacheName) {
		AbstractLoadingCache<Object, Object> cache = getCacheByName(cacheName);
		cache.getCache().invalidateAll();
		cache.setResetTime(new Date());
	}

	public static void refresh(String cacheName, String key) {
		AbstractLoadingCache<Object, Object> cache = getCacheByName(cacheName);
		cache.getCache().refresh(key);
		cache.setResetTime(new Date());
	}
}